using System;
using PropertyExpression.ReactiveRelation.Values;

namespace PropertyExpression.ReactiveRelation.Test.Demo
{
    internal static class CalcExecutorHolder
    {
        [ThreadStatic]
        private static ICalcExecutor calcExecutor;
        public static ICalcExecutor CalcExecutor
        {
            get
            {
                if (calcExecutor == null)
                {
                    calcExecutor = calcExecutorFactory();
                }
                return calcExecutor;
            }
        }

        private static readonly Func<ICalcExecutor> calcExecutorFactory = CalcStorageExtensions.CreateCalcExecutorFactory<IEmpty>(
            registrator =>
                {
                    registrator.Register<QuotePart>(
                        binder => binder.PartTotal(it => it.Quantity().Mult(it.Price()))
                        );

                    registrator.Register<QuoteJob>(
                        binder =>
                            {
                                binder.LaborSubtotal(it => it.LaborTime().Mult(it.LaborRate()));
                                binder.PartSubtotal(it => it.QuoteParts().Sum(part => part.PartTotal()));
                                binder.JobTotal(it => it.LaborSubtotal().Add(it.PartSubtotal()));
                            }
                        );

                    registrator.Register<Quote>(
                        binder =>
                            {
                                binder.PartSubtotal(it => it.QuoteJobs().Sum(job => job.PartSubtotal()));
                                binder.LaborSubtotal(it => it.QuoteJobs().Sum(job => job.LaborSubtotal()));
                                binder.OtherExpenseSubtotal(it => it.QuoteOtherExpenses()
                                    .Sum(expenses => expenses.OtherExpenseTotal()));
                                binder.QuoteTotal(it => it.QuoteJobs().Sum(job => job.JobTotal())
                                    .Add(it.OtherExpenseSubtotal()));
                            }
                        );

                    registrator.Register<QuoteOtherExpense>(
                        binder =>
                            {
                                binder.Price(it => Percent(it.Quote().LaborSubtotal(), it.LaborPercent())
                                              .Add(Percent(it.Quote().PartSubtotal(), it.PartPercent()))
                                              .Add(it.Fix()));
                                binder.OtherExpenseTotal(it => it.Quantity().Mult(it.Price()));
                            }
                        );
                }
            );

        private static IValue<decimal> Percent(IValue<decimal> baseValue, IValue<decimal> percentValue)
        {
            return baseValue.Percent(percentValue);
        }
    }

    internal interface IEmpty
    {        
    }
}